#include "triangulation.h"
#include <time.h>

int init_delaunay2D(DSC3D* dsc1, vtkDelaunay2D* del_out) {

	// create 3D points
	vtkPoints *points = vtkPoints::New();
	points->SetNumberOfPoints(dsc1->getVertexCount());
	for (int i = 0; i < dsc1->getVertexCount(); i++)
		points->SetPoint(i, dsc1->getVertices()[i]);

	vtkPolyData *profile = vtkPolyData::New();
	profile->SetPoints(points);
	
	del_out->SetInput(profile);
	del_out->SetTolerance(0.01);
	del_out->Update(); /* CRITICAL LINE */

#ifdef DEBUG
	cout << "===== TESTING VALIDITY OF TRIANGULATION RESULT =====" << endl;
	if (test_delaunay2D(points, del_out))
		return EXIT_FAILURE;
#endif

	points->Delete();
	profile->Delete();
	return 0;
}

int test_delaunay2D(vtkPoints* in_pts, vtkDelaunay2D* del_out) {
	
	vtkIdType inNumPts = in_pts->GetNumberOfPoints();
	cout << "input numPts = " << inNumPts << endl;
	
	vtkPolyData *tri = del_out->GetOutput();
	vtkIdType outNumPts = tri->GetNumberOfPoints();
	vtkIdType outNumCells = tri->GetNumberOfCells();
	vtkIdType outNumPolys = tri->GetNumberOfPolys();
	vtkIdType outNumLines = tri->GetNumberOfLines();
	vtkIdType outNumVerts = tri->GetNumberOfVerts();

	cout << "output numPts = " << outNumPts << endl;
	cout << "output numCells = " << outNumCells << endl;
	cout << "output numPolys = " << outNumPolys << endl;
	cout << "output numLines = " << outNumLines << endl;
	cout << "output numVerts = " << outNumVerts << endl;

	if (outNumPts != inNumPts ) {
		cout << "ERROR: output numPts " << outNumPts
			 << " doesn't match input numPts =" << inNumPts << endl;
		return EXIT_FAILURE;
    }
	
	if (!outNumCells) {
		cout << "ERROR: output numCells = " << outNumCells << endl;
		return EXIT_FAILURE;
    }

	if (outNumPolys != outNumCells) {
		cout << "ERROR: output numPolys = " << outNumPolys
			 << " doesn't match output numCells = " << outNumCells << endl;
		return EXIT_FAILURE;
    }

	if (outNumLines) {
		cout << "ERROR: output numLines = " << outNumLines << endl;
		return EXIT_FAILURE;
    }

	if (outNumVerts) {
		cout << "ERROR: output numVerts= " << outNumVerts << endl;
		return EXIT_FAILURE;
    }

#if 0	/* Cannot pass this test so far */
	// check that every point is connected
	tri->BuildLinks();
	
	vtkIdList *cellIds = vtkIdList::New();
	vtkIdType numUnconnectedPts = 0;
	
	for (vtkIdType ptId = 0; ptId < outNumPts; ptId++) {
		tri->GetPointCells(ptId,cellIds);
		if (!cellIds->GetNumberOfIds())
			numUnconnectedPts++;
    }
	cellIds->Delete();
	cout << "Triangulation has " << numUnconnectedPts
		 << " unconnected points" << endl;

	if (numUnconnectedPts) {
		cout << "ERROR: Triangulation has " << numUnconnectedPts
			 << " unconnected points" << endl;
		return EXIT_FAILURE;
    }
#endif

	return 0;
}

int export_delaunay2D(vtkDelaunay2D* del_out, char* filename) {
	
	string str = filename;
	char new_filename[256], dir[512], subdir[512];
	_getcwd(dir, 512);
	strcpy(subdir, dir);
	strcat(subdir, "\\wrl");

	// map to graphics library
	vtkDataSetMapper *map = vtkDataSetMapper::New();
	map->SetInputConnection(del_out->GetOutputPort());

	// actor coordinates geometry, properties, transformation
	vtkActor *triangulation = vtkActor::New();
	triangulation->SetMapper(map);
	triangulation->GetProperty()->SetColor(0.5,1,0.5); // mesh color blue

	// a renderer and render window
	vtkRenderer *ren1 = vtkRenderer::New();
	vtkRenderWindow *renWin = vtkRenderWindow::New();
	renWin->AddRenderer(ren1);
	
	// add the actor to the scene
	ren1->AddActor(triangulation);
	ren1->SetBackground(0,0,0); // Background color white

#ifndef MUTE
	// render an image (lights and cameras are created automatically)
	renWin->Render();
#endif

#ifdef SCRUTINIZE
	// an interactor
	vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
	iren->SetRenderWindow(renWin);

	// begin mouse interaction
	cout << "SCRUTINIZE MODE: close viewport to continue..." << endl;
	iren->Start();

	iren->Delete();
#endif

	vtkVRMLExporter *vrml = vtkVRMLExporter::New();
	vrml->SetInput(renWin);
	str = str.substr(0, str.length() - 5) + "wrl";
	strcpy(new_filename, str.c_str());
	vrml->SetFileName(new_filename);
	cout << "Exporting to " << new_filename << endl;
	_chdir(subdir);
	vrml->Write();
	_chdir(dir);
		
	map->Delete();
	triangulation->Delete();
	ren1->Delete();
	renWin->Delete();
	vrml->Delete();

	return 0;
}

int convert(char* filename) {
	
#if 0
	string str = filename;
	str = str.substr(str.length() - 5, str.length());
	if (str != "dsc3d") {
		cout << "Unknown format, skipping..." << endl;
		return 1;
	}
#endif
	
	cout << "==========" << endl
		 << "Converting " << filename << " ..." << endl;

	DSC3D *dsc1 = new DSC3D;
	dsc1->load_dsc3d_file(filename);

#ifdef DEBUG
	cout << "===== VERIFYING DATA LOADED FROM DSC3D FILE =====" << endl;
	dsc1->verify_loaded_data(5);
#endif
	
	vtkDelaunay2D *del = vtkDelaunay2D::New();
	if(init_delaunay2D(dsc1, del)) {
		cout << "Triangulation failure. Program terminated." << endl;
		exit(-1);
	}
	
	export_delaunay2D(del, filename);

	del->Delete();

	delete dsc1;
	return 0;
}

#ifdef MULTI_THREAD
char fileName[8][512];
int totalDone = 0, threadNo = -1;
void threadConvert(PVOID param) {
	//cout << "I am running" << endl;
	threadNo++;
	convert(fileName[threadNo]);
	totalDone++;
}
#endif

int convert_dir(char* dir) {
	
	char str[512];
	int count = 0;
	DirectoryListing cur_dir;
	
	cout << "Batch processing directory: " << dir << endl;
	
	cur_dir.First(str, "*.dsc3d");
	if (!strlen(str)) {	
		cout << "No DSC3D file was found." << endl;	
		return 1;	
	}

	create_wrl_dir();

	clock_t start = clock(), finish;
	do {
#ifdef MULTI_THREAD
		strcpy(fileName[count], str);
		_beginthread(threadConvert, 0, NULL);
#else
		convert(str);
#endif
		count++;
	} while (cur_dir.Next(str));

#ifdef MULTI_THREAD
	while (totalDone != count) ;
#endif
	finish = clock();
	cout << count << " DSC3D file(s) processed." << endl;
	cout << "Total time elapsed: " << float(finish - start)/1000 << " seconds" << endl;

	return 0;
}

int create_wrl_dir() {
	
	char str[512];

	if (_mkdir(strcat(_getcwd(str, 512), "\\wrl")) == -1) {
		cout << "The directory \\wrl already exists, potential danger of overwrites." << endl;
		return 1;
	}

	return 0;
}